package com.bihua.iot.service.impl;

import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bihua.common.core.domain.PageQuery;
import com.bihua.common.core.page.TableDataInfo;
import com.bihua.common.utils.BeanCopyUtils;
import com.bihua.common.utils.StringUtils;
import com.bihua.iot.domain.DeviceInfo;
import com.bihua.iot.domain.TdFields;
import com.bihua.iot.domain.TdSelect;
import com.bihua.iot.domain.TdTable;
import com.bihua.iot.domain.bo.DeviceInfoBo;
import com.bihua.iot.domain.bo.ProductBo;
import com.bihua.iot.domain.bo.ProductServicesBo;
import com.bihua.iot.domain.vo.DeviceInfoVo;
import com.bihua.iot.domain.vo.DeviceVo;
import com.bihua.iot.domain.vo.ProductServicesVo;
import com.bihua.iot.domain.vo.ProductVo;
import com.bihua.iot.enums.DeviceConnectStatus;
import com.bihua.iot.mapper.DeviceInfoMapper;
import com.bihua.iot.service.IDeviceInfoService;
import com.bihua.iot.service.IDeviceService;
import com.bihua.iot.service.IProductService;
import com.bihua.iot.service.IProductServicesService;
import com.bihua.iot.service.TdEngineService;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 子设备档案Service业务层处理
 *
 * @author bihua
 * @date 2023-06-16
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class DeviceInfoServiceImpl implements IDeviceInfoService {

    private final DeviceInfoMapper baseMapper;
    private final IDeviceService iDeviceService;
    private final IProductService iProductService;
    private final IProductServicesService iProductServicesService;
    private final TdEngineService tdEngineService;

    @Value("${spring.datasource.dynamic.datasource.td.dbName:bihua}")
    private String dataBaseName;
    /**
     * 查询子设备档案
     */
    @Override
    public DeviceInfoVo queryById(Long id){
        DeviceInfoVo vo = baseMapper.selectVoById(id);
        if (ObjectUtil.isNotEmpty(vo)) {
            DeviceVo oneById = iDeviceService.queryById(vo.getDid());
            vo.setEdgeDevicesIdentification(ObjectUtil.isNotEmpty(oneById)?oneById.getDeviceIdentification():"");
        }
        return vo;
    }

    /**
     * 查询子设备档案列表
     */
    @Override
    public TableDataInfo<DeviceInfoVo> queryPageList(DeviceInfoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<DeviceInfo> lqw = buildQueryWrapper(bo);
        Page<DeviceInfoVo> result = baseMapper.selectPageList(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询子设备档案列表
     */
    @Override
    public List<DeviceInfoVo> queryList(DeviceInfoBo bo) {
        LambdaQueryWrapper<DeviceInfo> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<DeviceInfo> buildQueryWrapper(DeviceInfoBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<DeviceInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getDid() != null, DeviceInfo::getDid, bo.getDid());
        lqw.eq(StringUtils.isNotBlank(bo.getNodeId()), DeviceInfo::getNodeId, bo.getNodeId());
        lqw.like(StringUtils.isNotBlank(bo.getNodeName()), DeviceInfo::getNodeName, bo.getNodeName());
        lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceInfo::getDeviceId, bo.getDeviceId());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), DeviceInfo::getDescription, bo.getDescription());
        lqw.eq(StringUtils.isNotBlank(bo.getModel()), DeviceInfo::getModel, bo.getModel());
        lqw.eq(StringUtils.isNotBlank(bo.getConnectStatus()), DeviceInfo::getConnectStatus, bo.getConnectStatus());
        lqw.eq(bo.getShadowEnable() != null, DeviceInfo::getShadowEnable, bo.getShadowEnable());
        lqw.like(StringUtils.isNotBlank(bo.getShadowTableName()), DeviceInfo::getShadowTableName, bo.getShadowTableName());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), DeviceInfo::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增子设备档案
     */
    @Override
    public Boolean insertByBo(DeviceInfoBo bo) {
        DeviceInfo add = BeanUtil.toBean(bo, DeviceInfo.class);
        //add.setDeviceId(UUID.fastUUID().toString());
        add.setConnectStatus(DeviceConnectStatus.INIT.getValue());
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改子设备档案
     */
    @Override
    public Boolean updateByBo(DeviceInfoBo bo) {
        DeviceInfo update = BeanUtil.toBean(bo, DeviceInfo.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(DeviceInfo entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除子设备档案
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 刷新子设备数据模型
     * @param idCollection
     * @return
     */
    @Override
    public Boolean refreshDeviceInfoDataModel(Collection<Long> idCollection) {
        List<DeviceInfoVo> allByIdInAndStatus = null;
        if (CollectionUtil.isNotEmpty(idCollection)) {
            allByIdInAndStatus = baseMapper.selectVoBatchIds(idCollection).stream().filter(new Predicate<DeviceInfoVo>() {
                @Override
                public boolean test(DeviceInfoVo infoVo) {
                    return StringUtils.equalsIgnoreCase(infoVo.getStatus(), "0");
                }
            }).collect(Collectors.toList());
        }else {
            return false;
        }
        allByIdInAndStatus.forEach(item->{
            final DeviceVo device = iDeviceService.queryById(item.getDid());
            if (ObjectUtil.isNull(device)) {
                log.error("刷新子设备数据模型失败，子设备不存在");
                return;
            }
            ProductBo bo = new ProductBo();
            bo.setProductIdentification(device.getProductIdentification());
            bo.setProtocolType(device.getProtocolType());
            List<ProductVo> products = iProductService.queryList(bo);
            if (CollectionUtil.isEmpty(products)) {
                log.error("刷新子设备数据模型失败，子设备产品不存在");
                return;
            }
            StringBuilder shadowTableNameBuilder = new StringBuilder();
            // 新增设备管理成功后，创建TD普通表
            ProductServicesBo servicesBo = new ProductServicesBo();
            servicesBo.setProductIdentification(device.getProductIdentification());
            servicesBo.setStatus("0");
            List<ProductServicesVo> allByProductIdAndStatus = iProductServicesService.queryList(servicesBo);
            TdTable tableDto;
            for (ProductServicesVo productServices : allByProductIdAndStatus) {
                tableDto = new TdTable();
                tableDto.setDataBaseName(dataBaseName);
                //超级表命名规则 : 产品类型_产品标识_服务名称
                String superTableName = products.get(0).getProductType() + "_" + productServices.getProductIdentification() + "_" + productServices.getServiceName();

                tableDto.setSuperTableName(superTableName);
                //子表命名规则 : 产品类型_产品标识_服务名称_设备标识（设备唯一标识）
                tableDto.setTableName(superTableName + "_" + item.getDeviceId());
                //Tag的处理
                List<TdFields> tagsFieldValues = new ArrayList<>();
                TdFields fields = new TdFields();
                fields.setFieldValue(device.getDeviceIdentification());
                tagsFieldValues.add(fields);
                tableDto.setTagsFieldValues(tagsFieldValues);
                try {
                    tdEngineService.createTable(tableDto);
                    shadowTableNameBuilder.append(tableDto.getTableName()).append(",");
                    log.info("Create SuperTable Success: " + tableDto.getTableName());
                } catch (Exception e) {
                    log.error("Create SuperTable Exception: " + e.getMessage());
                }
            }
            if (shadowTableNameBuilder.length() > 0) {
                item.setShadowTableName(shadowTableNameBuilder.substring(0, shadowTableNameBuilder.length() - 1));
            }
            shadowTableNameBuilder.replace(0, shadowTableNameBuilder.length(), "");
            item.setCreateBy(device.getCreateBy());
            baseMapper.updateById(BeanCopyUtils.copy(item, DeviceInfo.class));
        });
        return true;
    }
    /**
     * 查询子设备影子数据
     *
     * @param ids 需要查询的子设备id
     * @param startTime 开始时间 格式：yyyy-MM-dd HH:mm:ss
     * @param endTime 结束时间 格式：yyyy-MM-dd HH:mm:ss
     * @return 子设备影子数据
     */
    @Override
    public Map<String, List<Map<String, Object>>> getDeviceInfoShadow(String ids,String startTime,String endTime) {
        List<Long> idCollection = Arrays.stream(ids.split(",")).mapToLong(Long::parseLong).boxed().collect(Collectors.toList());
        List<DeviceInfoVo> deviceInfos = baseMapper.selectVoBatchIds(idCollection).stream().filter(new Predicate<DeviceInfoVo>() {
            @Override
            public boolean test(DeviceInfoVo infoVo) {
                return StringUtils.equalsIgnoreCase(infoVo.getStatus(), "0");
            }
        }).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(deviceInfos)) {
            log.error("查询子设备影子数据失败，子设备不存在");
            return null;
        }
        Map<String, List<Map<String, Object>>> map = new HashMap<>();
        deviceInfos.forEach(deviceInfo -> {
            if (StringUtils.isEmpty(deviceInfo.getShadowTableName())) {
                log.error("查询子设备影子数据失败，子设备影子表名为空");
                return;
            }
            List<String> shadowTableNameCollect = Stream.of(deviceInfo.getShadowTableName().split(",")).collect(Collectors.toList());
            shadowTableNameCollect.forEach(shadowTableName -> {
                TdSelect selectDto = new TdSelect();
                selectDto.setDataBaseName(dataBaseName);
                selectDto.setTableName(shadowTableName);
                if (StringUtils.isNotEmpty(startTime) && StringUtils.isNotEmpty(endTime)) {
                    selectDto.setFieldName("ts");
                    selectDto.setStartTime(DateUtil.parseLocalDateTime(startTime).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                    selectDto.setEndTime(DateUtil.parseLocalDateTime(endTime).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                    List<Map<String, Object>> dataByTimestamp = tdEngineService.selectByTimesTamp(selectDto);
                    if (CollectionUtil.isEmpty(dataByTimestamp)) {
                        log.error("查询子设备影子数据失败，子设备影子数据不存在");
                    }else {
                        map.put(shadowTableName, dataByTimestamp);
                        log.info("查询子设备影子数据成功，子设备影子数据：{}", dataByTimestamp);
                    }
                }else{
                    List<Map<String, Object>> lastData = tdEngineService.getLastData(selectDto);
                    if (CollectionUtil.isEmpty(lastData)) {
                        log.error("查询子设备影子数据失败，子设备影子数据不存在");
                    }else {
                        map.put(shadowTableName, lastData);
                        log.info("查询子设备影子数据成功，子设备影子数据：{}", lastData);
                    }
                }
            });
        });
        return map;
    }

    @Override
    public int deleteByDeviceIds(List<String> deviceIds) {
        return baseMapper.delete(new LambdaQueryWrapper<DeviceInfo>().in(DeviceInfo::getDeviceId, deviceIds));
    }

    @Override
    public DeviceInfoVo findOneByDeviceId(String deviceId) {
        DeviceInfo info = baseMapper.findOneByDeviceId(deviceId);
        if (ObjectUtil.isNull(info)) {
            return null;
        }
        return BeanCopyUtils.copy(info, DeviceInfoVo.class);
    }
}
